package com.symaster.common.swing.element;

import com.symaster.common.ConsolePanel;
import com.symaster.common.swing.util.SwingUtil;
import com.symaster.common.util.CommonUtil;
import com.symaster.common.util.ProbabilityUtil;

import javax.swing.*;
import java.awt.*;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author yinmiao
 * @date 2022-03-29 10:55
 */
public class ConsolePanelOfList extends JPanel implements ConsolePanel {

    public static final int ERR = 1;
    public static final int INFO = 0;
    public static final int WING = 2;
    public static final int DEBUG = 3;

    public static Color errorColor;
    public static Color infoColor;
    public static Color warningColor;
    public static Color debugColor;
    public int maxRow = 1000;
    private boolean debug = false;
    private JList jList;
    private DefaultListModel<MessageItem> listModel;
    private JToggleButton debugToggleButton;
    private boolean toBottom = true;

    public ConsolePanelOfList() {
        initDefaultColor();
        initPage();
    }

    public static void main(String[] args) throws InterruptedException {
        JFrame jFrame = new JFrame();
        ConsolePanelOfList consolePanelOfList = new ConsolePanelOfList();
        consolePanelOfList.setDebugStatus(true);
        jFrame.setContentPane(consolePanelOfList);
        jFrame.setPreferredSize(new Dimension(400, 700));
        jFrame.pack();
        SwingUtil.toCenter(jFrame);
        jFrame.setVisible(true);

        while (true) {
            if (ProbabilityUtil.exeProbability(0.2)) {
                consolePanelOfList.debug(UUID.randomUUID().toString());
            }
            if (ProbabilityUtil.exeProbability(0.2)) {
                consolePanelOfList.print(UUID.randomUUID().toString());
            }
            TimeUnit.MILLISECONDS.sleep(5);
        }
    }

    public static Color getErrorColor() {
        return errorColor;
    }

    public static Color getInfoColor() {
        return infoColor;
    }

    public static Color getWarningColor() {
        return warningColor;
    }

    public static Color getDebugColor() {
        return debugColor;
    }

    public boolean getDebugStatus() {
        return this.debug;
    }

    public void setDebugStatus(boolean debug) {
        this.debug = debug;
        SwingUtilities.invokeLater(() -> this.debugToggleButton.setSelected(debug));
    }

    private void initDefaultColor() {
        errorColor = UIManager.getColor("error.color");
        if (errorColor == null) {
            errorColor = new Color(245, 108, 108);
        }
        warningColor = UIManager.getColor("warning.color");
        if (warningColor == null) {
            warningColor = new Color(230, 162, 60);
        }
        infoColor = UIManager.getColor("TextField.foreground");
        if (infoColor == null) {
            infoColor = new Color(0, 0, 0);
        }
        debugColor = UIManager.getColor("debug.color");
        if (debugColor == null) {
            debugColor = new Color(45, 45, 45);
        }
    }

    private void initPage() {
        setLayout(new BorderLayout());
        listModel = new DefaultListModel<>();
        jList = new JList(listModel);
        jList.setCellRenderer(new ConsoleListPanelRenderer());
        JScrollPane scrollPane = new JScrollPane();
        scrollPane.setViewportView(jList);
        add(scrollPane);
        JComponent toolBar = getToolBar();
        add(toolBar, BorderLayout.EAST);
    }

    private JComponent getToolBar() {

        JToolBar a = new JToolBar();
        a.setFloatable(false);
        a.setOrientation(JToolBar.VERTICAL);
        a.setPreferredSize(new Dimension(25, 25));
        JToggleButton jToggleButton = new JToggleButton();
        jToggleButton.setIcon(SwingUtil.loadIcon("down_to_bottom.png", 18, 18));
        jToggleButton.setSelected(true);
        jToggleButton.addActionListener(e -> SwingUtilities.invokeLater(() -> {
            if (toBottom) {
                toBottom = false;
                jToggleButton.setSelected(false);
            } else {
                toBottom = true;
                jToggleButton.setSelected(true);
            }
        }));
        a.add(jToggleButton);

        JButton jButton = new JButton();
        jButton.setIcon(SwingUtil.loadIcon("delete.png", 18, 18));
        jButton.addActionListener(e -> SwingUtilities.invokeLater(() -> {
            listModel.removeAllElements();
        }));
        a.add(jButton);

        this.debugToggleButton = new JToggleButton();
        this.debugToggleButton.setIcon(SwingUtil.loadIcon("debug.png", 15, 15));
        this.debugToggleButton.setSelected(false);
        this.debugToggleButton.addActionListener(e -> SwingUtilities.invokeLater(() -> {
            if (debug) {
                debug = false;
                debugToggleButton.setSelected(false);
            } else {
                debug = true;
                debugToggleButton.setSelected(true);
            }
        }));
        a.add(this.debugToggleButton);
        return a;
    }

    public MessageItem getMessageItem(String message, int type) {
        return new MessageItem(message, type);
    }

    private void print(String message, int type) {
        SwingUtilities.invokeLater(() -> {
            if (listModel.size() > maxRow) {
                listModel.removeRange(0, maxRow / 2);
            }
            MessageItem messageItem = getMessageItem(message, type);
            listModel.addElement(messageItem);
            if (toBottom) {
                jList.ensureIndexIsVisible(listModel.size() - 1);
            }
        });
    }

    @Override
    public void debug(String str, Object... args) {
        debug(String.format(str, args));
    }

    @Override
    public void debug(String message) {
        if (debug) {
            print(String.format("[debug] %s", message), DEBUG);
        }
    }

    @Override
    public JPanel getRootPanel() {
        return this;
    }

    @Override
    public void printlnErr(String message) {
        print(message, ERR);
    }

    @Override
    public void printErr(String message) {
        print(message, ERR);
    }

    @Override
    public void println(String message) {
        print(message, INFO);
    }

    @Override
    public void print(String message) {
        print(message, INFO);
    }

    @Override
    public void printf(String str, Object... args) {
        print(String.format(str, args), INFO);
    }

    @Override
    public void printfErr(String str, Object... args) {
        print(String.format(str, args), ERR);
    }
}

class MessageItem {
    private String message;
    private int messageType;

    public MessageItem() {
    }

    public MessageItem(String message, int messageType) {
        this.message = message;
        this.messageType = messageType;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public int getMessageType() {
        return messageType;
    }

    public void setMessageType(int messageType) {
        this.messageType = messageType;
    }

    @Override
    public String toString() {
        return "MessageItem{" +
                "message='" + message + '\'' +
                ", messageType=" + messageType +
                '}';
    }
}

class ConsoleListPanelRenderer extends JLabel implements ListCellRenderer {
    private static final Color HIGHLIGHT_COLOR = new Color(0, 0, 128);

    public ConsoleListPanelRenderer() {
        setBackground(new Color(0, 0, 0, 0));
    }

    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
        if (value instanceof MessageItem) {
            MessageItem value1 = (MessageItem) value;
            setText(value1.getMessage());
            setColor(list, value1.getMessageType());
        } else {
            setText(value.toString());
            setColor(list, ConsolePanelOfList.WING);
        }
        return this;
    }

    private void setColor(JList list, int type) {

        Color errorColor = ConsolePanelOfList.getErrorColor();
        Color infoColor = ConsolePanelOfList.getInfoColor();
        Color warningColor = ConsolePanelOfList.getWarningColor();
        Color debugColor = ConsolePanelOfList.getDebugColor();

        if (ConsolePanelOfList.INFO == type) {
            setForeground(infoColor);
            return;
        }
        if (ConsolePanelOfList.WING == type) {
            setForeground(warningColor);
            return;
        }
        if (ConsolePanelOfList.ERR == type) {
            setForeground(errorColor);
        }
        if (ConsolePanelOfList.DEBUG == type) {
            setForeground(debugColor);
        }
    }
}


